﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SharedLib.WinFormMVCFramework;
using TracyGUI.View.UIComponent;
using Tracy;
using SharedLib;
using Tracy.DataModel;
using TracyGUI.View.EntryTabs;
using System.Xml;
using System.IO;
using TracyGUI.Model;
using SharedLib.Helpers;
using System.Reflection;

namespace TracyGUI.View
{
    public partial class FormMain : WinFormViewBase, IMainView, IEntryListView, IUltraExplorerView, IEntryTabsView, ITracyConfigView, IStatisticsView, IDownloadCheckListView, IImportExportView, INotifyIconView
    {
        public FormMain()
        {
            InitializeComponent();
            //Adjust splitContainer layout
            splitContainerUE.SplitterDistance = 21;

            //Set notification icon
            this.Icon = SharedResource.Tracy;
            notifyIconMain.Icon = SharedResource.Tracy;
            Text = AssemblyHelper.GetAssemblyTitle(Assembly.GetExecutingAssembly());
        }

        public override void ApplyLanguage(LanguageManager manager)
        {
            base.ApplyLanguage(manager);
            if (manager != null)
            {
                toolStripStatusLabelMain.Text = manager.GetText("StatusReady");
                toolStripTextBoxSearch.Text = manager.GetText("TypeToSearch");
                toolStripButtonAutoMode.Text = TracyFacade.Instance.LanguageManager.GetText("AutoModeOff");
                manager.ApplyLanguage(this.Name, notifyIconMain.ContextMenuStrip);
            }
        }

        #region MainView
        public event EventHandler ShowAboutClicked;
        public event EventHandler ScanClicked;

        AboutBoxMain _aboutBox;
        public void ShowAbout()
        {
            InvokeOnUIThread(() =>
            {
                if (_aboutBox == null || _aboutBox.IsDisposed) _aboutBox = new AboutBoxMain();
                _aboutBox.Show();
            });
        }

        private void ShowAndActivate()
        {
            if (this.WindowState == FormWindowState.Minimized) this.WindowState = FormWindowState.Normal;
            this.Activate();
        }

        private void toolStripButtonAbout_Click(object sender, EventArgs e)
        {
            ShowAboutClicked.InvokeEvent(this, e);
        }

        private void toolStripButtonScan_Click(object sender, EventArgs e)
        {
            ScanClicked.InvokeEvent(this, e);
        }
        #endregion

        #region EntryListView
        bool _isUpdatingEntry = false;
        public event EventHandler CreateEntryClicked;
        public event EventHandler<GenericEventArgs<Entry>> EditEntryClicked;
        public event EventHandler<GenericEventArgs<Entry>> RemoveEntryClicked;

        public event EventHandler<GenericEventArgs<Entry>> EntrySelected;
        public event EventHandler<GenericEventArgs<Entry>> OpenEntryInNewTab;
        public event EventHandler AllEntriesClicked;
        #region UI Operations
        public void LoadEntry(Tracy.DataModel.Entry entry)
        {
            InvokeOnUIThread(() =>
            {
                ListBoxItemEntry item = new ListBoxItemEntry(entry);
                listBoxEntries.Items.Insert(0, item);
            });
        }

        public void ClearEntries()
        {
            InvokeOnUIThread(() =>
            {
                listBoxEntries.Items.Clear();
            });
        }
        private int GetEntryIndex(Entry entry)
        {
            int index = -1;
            for (int i = 0; i < listBoxEntries.Items.Count; i++)
            {
                if ((listBoxEntries.Items[i] as ListBoxItemEntry).Data.ID == entry.ID)
                {
                    index = i;
                    break;
                }
            }
            return index;
        }
        public void RefreshEntry(Entry entry)
        {
            InvokeOnUIThread(() =>
            {
                int index = GetEntryIndex(entry);
                if (index >= 0)
                {
                    //Only refresh visible entry
                    _isUpdatingEntry = true;
                    listBoxEntries.Items.RemoveAt(index);
                    ListBoxItemEntry item = new ListBoxItemEntry(entry);
                    listBoxEntries.Items.Insert(index, item);
                    //listBoxEntries.SelectedIndex = index;
                    _isUpdatingEntry = false;
                }
            });
        }
        
        public void UnloadEntry(Entry entry)
        {
            InvokeOnUIThread(() =>
            {
                int index = GetEntryIndex(entry);
                if (index >= 0)
                {
                    _isUpdatingEntry = true;
                    listBoxEntries.Items.RemoveAt(index);
                    _isUpdatingEntry = false;
                }
            });
        }

        public void SelectEntry(Entry entry)
        {
            InvokeOnUIThread(() =>
            {
                int index = GetEntryIndex(entry);
                if (index >= 0)
                {
                    listBoxEntries.SelectedIndex = index;
                }
            });
        }
        #endregion

        private Entry GetSelectedEntry()
        {
            if (listBoxEntries.SelectedIndex != -1)
            {
                ListBoxItemEntry item = listBoxEntries.SelectedItem as ListBoxItemEntry;
                return item.Data;
            }
            return null;
        }

        private void listBoxEntries_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (!_isUpdatingEntry)
            { 
                Entry entry = GetSelectedEntry();
                if(entry != null) EntrySelected.InvokeEvent(this, new GenericEventArgs<Entry> (entry));
            }
        }
        private void openInNewTabToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Entry entry = GetSelectedEntry();
            if (entry != null) OpenEntryInNewTab.InvokeEvent(this, new GenericEventArgs<Entry>(entry));
        }
        private void toolStripButtonShowAll_Click(object sender, EventArgs e)
        {
            AllEntriesClicked.InvokeEvent(this, null);
        }
        
        private void toolStripButtonAddEntry_Click(object sender, EventArgs e)
        {
            CreateEntryClicked.InvokeEvent(this, e);
        }
        private void toolStripMenuItemAddEntry_Click(object sender, EventArgs e)
        {
            CreateEntryClicked.InvokeEvent(this, e);
        }
        private void toolStripMenuItemModifyEntry_Click(object sender, EventArgs e)
        {
            Entry entry = GetSelectedEntry();
            if (entry != null) EditEntryClicked.InvokeEvent(this, new GenericEventArgs<Entry>(entry));
        }
        private void listBoxEntries_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            Entry entry = GetSelectedEntry();
            if (entry != null) EditEntryClicked.InvokeEvent(this, new GenericEventArgs<Entry>(entry));
        }
        private void toolStripMenuItemRemoveEntry_Click(object sender, EventArgs e)
        {
            Entry entry = GetSelectedEntry();
            if (entry != null) RemoveEntryClicked.InvokeEvent(this, new GenericEventArgs<Entry>(entry));
        }

        #region UI Experience Enhancement
        private void contextMenuStripEntry_Opening(object sender, CancelEventArgs e)
        {
            if (listBoxEntries.SelectedIndex == -1)
            {
                toolStripMenuItemModifyEntry.Enabled = false;
                toolStripMenuItemRemoveEntry.Enabled = false;
            }
            else
            {
                toolStripMenuItemModifyEntry.Enabled = true;
                toolStripMenuItemRemoveEntry.Enabled = true;
            }
        }
        private void listBoxEntries_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Right)//Select item on right click
            {
                int selectedIndex = listBoxEntries.IndexFromPoint(e.X, e.Y);
                if (selectedIndex != -1)
                {
                    listBoxEntries.SelectedIndex = selectedIndex;
                }
            }
        }
        private void listBoxEntries_DrawItem(object sender, DrawItemEventArgs e)
        {
            if (e.Index >= 0)
            {
                e.DrawBackground();
                ListBoxItemEntry item = listBoxEntries.Items[e.Index] as ListBoxItemEntry;
                if (item != null)
                {
                    Font myFont = e.Font;
                    Brush myBrush = SystemBrushes.WindowText;
                    if (item.Data.TracingDisabled) myBrush = SystemBrushes.GrayText;
                    if (item.UnWatchedCount > 0) myBrush = Brushes.DarkRed; //myFont = new Font(myFont, FontStyle.Bold);
                    e.Graphics.DrawString(item.ToString(), myFont, myBrush, e.Bounds, StringFormat.GenericDefault);
                }
                e.DrawFocusRectangle();
            }
        }
        #endregion

        #region Search
        public event EventHandler<GenericEventArgs<string>> Search;
        public void FocusOnSearchTextBox()
        {
            InvokeOnUIThread(() =>
            {
                if (!toolStripTextBoxSearch.Focused)
                    toolStripTextBoxSearch.Focus();
            });
        }
        private void toolStripTextBoxSearch_Click(object sender, EventArgs e)
        {
            toolStripTextBoxSearch.SelectAll();
        }
        private void toolStripTextBoxSearch_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == 13)
            {
                if (!String.IsNullOrEmpty(toolStripTextBoxSearch.Text) && toolStripTextBoxSearch.Text != TracyFacade.Instance.LanguageManager.GetText("TypeToSearch"))
                    Search.InvokeEvent(this, new GenericEventArgs<string>(toolStripTextBoxSearch.Text));
            }
        }
        private void toolStripTextBoxSearch_TextChanged(object sender, EventArgs e)
        {
            if (!String.IsNullOrEmpty(toolStripTextBoxSearch.Text) && toolStripTextBoxSearch.Text != TracyFacade.Instance.LanguageManager.GetText("TypeToSearch"))
                Search.InvokeEvent(this, new GenericEventArgs<string>(toolStripTextBoxSearch.Text));
        }
        #endregion

        #endregion

        #region UltraExplorerView
        public event EventHandler<GenericEventArgs<string>> ClassiferSetSelected;
        public event EventHandler<GenericEventArgs<TreeNode>> ExpandNode;
        public event EventHandler<GenericEventArgs<TreeNode>> NodeSelected;

        public TreeView TreeFilter
        {
            get { return treeViewEntryUE; }
        }
        #region UI Operations
        public void LoadClassiferSets(ICollection<string> classifierSetNames)
        {
            InvokeOnUIThread(() =>
            {
                foreach (string classifierSet in classifierSetNames)
                {
                    comboBoxUE.Items.Add(new ListBoxItemValueText(classifierSet, TracyFacade.Instance.LanguageManager.GetText("ClassifierSet_" + classifierSet)));
                }
                if (comboBoxUE.Items.Count > 0) comboBoxUE.SelectedIndex = 0;
            });
        }
        public void SelectClassifierSet(string classifierSetName)
        {
            InvokeOnUIThread(() =>
            {
                if (String.IsNullOrEmpty(classifierSetName))
                {
                    comboBoxUE.SelectedIndex = -1;
                }
                else
                {
                    comboBoxUE.SelectByValue(classifierSetName);
                }
            });
        }
        #endregion
        private void comboBoxUE_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (comboBoxUE.SelectedIndex >= 0)
            {
                ClassiferSetSelected.InvokeEvent(this, new GenericEventArgs<string> (comboBoxUE.GetSelectedValue()));
            }
        }
        private void treeViewEntryUE_AfterSelect(object sender, TreeViewEventArgs e)
        {
            if (e.Action != TreeViewAction.Unknown)
            {
                NodeSelected.InvokeEvent(this, new GenericEventArgs<TreeNode>(e.Node));
            }
        }
        private void treeViewEntryUE_BeforeExpand(object sender, TreeViewCancelEventArgs e)
        {
            ExpandNode.InvokeEvent(this, new GenericEventArgs<TreeNode>(e.Node));
        }
        #endregion

        #region EntryTabsView
        private EnhancedTabControl<TabPageEntry> _tabControlContent;
        public EnhancedTabControl<TabPageEntry> EntryTabControl
        {
            get {
                if (_tabControlContent == null)
                {
                    _tabControlContent = new EnhancedTabControl<TabPageEntry>();
                    splitContainerV.Panel2.Controls.Add(_tabControlContent);
                    _tabControlContent.Dock = DockStyle.Fill;
                    _tabControlContent.AllowDrop = true;
                    //_tabControlContent.PageRemoved += new EventHandler<TabPageEvent>(tabControlContent_PageRemoved); TODO
                }
                return _tabControlContent;
            }
        }
        #endregion

        #region ConfigView
        public event EventHandler AutoDownloadModeSwitched;
        public void DisplayAutoDownloadMode(string mode)
        {
            InvokeOnUIThread(() =>
            {
                toolStripButtonAutoMode.Text = mode;
            });
        }
        public void AddConfigMenu(string text, EventHandler callback)
        {
            InvokeOnUIThread(() =>
            {
                settingsToolStripMenuItem.Visible = true;
                ToolStripMenuItem menuItem = new ToolStripMenuItem(text);
                menuItem.Click += new EventHandler(callback);
                settingsToolStripMenuItem.DropDownItems.Add(menuItem);
            });
        }

        private void toolStripButtonAutoMode_Click(object sender, EventArgs e)
        {
            AutoDownloadModeSwitched.InvokeEvent(this, e);
        }
        #endregion

        #region StatisticsView
        #region UI Operations
        public void DisplayStatusText(string statusText)
        {
            InvokeOnUIThread(() =>
            {
                toolStripStatusLabelMain.Text = statusText;
            });
        }
        #endregion
        #endregion

        #region DownloadCheckListView


        public event EventHandler<GenericEventArgs<List<Resource>>> ResourceSelectionConfirmed;
        FormSelection<ListBoxItemResource> _formNewResourceSelection;
        #region UI Operations
        public void ShowResourceForDownload(Resource res)
        {
            InvokeOnUIThread(() =>
            {
                if (_formNewResourceSelection == null || _formNewResourceSelection.IsDisposed)
                {
                    _formNewResourceSelection = new FormSelection<ListBoxItemResource>(TracyFacade.Instance.LanguageManager.GetText("FormSelection_NewResourceFound_Title"), TracyFacade.Instance.LanguageManager.GetText("FormSelection_NewResourceFound_Message"), false);
                    _formNewResourceSelection.SelectionConfirmed += new EventHandler<GenericEventArgs<List<ListBoxItemResource>>>(_formNewResourceSelection_SelectionConfirmed);
                }
                _formNewResourceSelection.AddItem(new ListBoxItemResource(res));
            });
        }

        #endregion
        void _formNewResourceSelection_SelectionConfirmed(object sender, GenericEventArgs<List<ListBoxItemResource>> e)
        {
            List<Resource> resList = new List<Resource>();
            foreach (ListBoxItemResource item in e.Data)
            {
                resList.Add(item.Data);
            }
            ResourceSelectionConfirmed.InvokeEvent(this, new GenericEventArgs<List<Resource>>(resList));
        }

        #endregion

        #region DataImportView

        public event EventHandler<GenericEventArgs<string>> DataImportFileSelected;
        public event EventHandler<EnhancedEventArgs> DataExporting;
        public event EventHandler<EnhancedEventArgs> PhysicalFilesImporting;
        private void importToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (openFileDialogMain.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                DataImportFileSelected.InvokeEvent(this, new GenericEventArgs<string>(openFileDialogMain.FileName));
            }
        }
        private void exportToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FormSelection<ListBoxItemEntry> entrySelectionForm = new FormSelection<ListBoxItemEntry>(TracyFacade.Instance.LanguageManager.GetText("FormSelection_ExportEntries_Title"), TracyFacade.Instance.LanguageManager.GetText("FormSelection_ExportEntries_Message"), true);
            foreach (ListBoxItemEntry item in listBoxEntries.Items)
            {
                entrySelectionForm.AddItem(item);
            }
            if (entrySelectionForm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                if (saveFileDialogMain.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    List<Entry> entriesToExport = new List<Entry>();
                    foreach (ListBoxItemEntry item in entrySelectionForm.GetSelectedItems())
                    {
                        entriesToExport.Add(item.Data);
                    }
                    if (entriesToExport.Count > 0)
                    {
                        EnhancedEventArgs args = new EnhancedEventArgs();
                        args.Attributes.Add("file", saveFileDialogMain.FileName);
                        args.Attributes.Add("entries", entriesToExport);
                        DataExporting.InvokeEvent(this, args);
                    }
                }
            }
        }

        private void importFolderToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //Select folder to be imported
            if (folderBrowserDialogMain.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                //Select files to be imported
                FormSelection<UIDataWrapper<string>> fileSelection = new FormSelection<UIDataWrapper<string>>(TracyFacade.Instance.LanguageManager.GetText("FormSelection_ImportFiles_Title"), TracyFacade.Instance.LanguageManager.GetText("FormSelection_ImportFiles_Message"), true);
                foreach (string filePath in Directory.EnumerateFiles(folderBrowserDialogMain.SelectedPath, "*.*", SearchOption.AllDirectories))
                {
                    fileSelection.AddItem(new UIDataWrapper<string>(filePath, Path.GetFileName(filePath)));
                }

                if (fileSelection.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    FormInput inputForm = new FormInput() { Message = TracyFacade.Instance.LanguageManager.GetText("FormInput_EnterEntryName_Message"), Value = folderBrowserDialogMain.SelectedPath.Substring(folderBrowserDialogMain.SelectedPath.LastIndexOf("\\") + 1) };
                    if (inputForm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    {
                        List<string> selectedFiles = new List<string>();
                        foreach (UIDataWrapper<string> item in fileSelection.GetSelectedItems())
                        {
                            selectedFiles.Add(item.Data);
                        }
                        if (selectedFiles.Count > 0)
                        {
                            EnhancedEventArgs args = new EnhancedEventArgs();
                            args.Attributes.Add("entry-name", inputForm.Value);
                            args.Attributes.Add("save-path", folderBrowserDialogMain.SelectedPath);
                            args.Attributes.Add("files", selectedFiles);
                            PhysicalFilesImporting.InvokeEvent(this, args);
                        }
                    }
                }
            }
        }

        #region UI Operations
        public void ShowAvailableEntries(List<Entry> entries, Action<List<Entry>> callback)
        {
            InvokeOnUIThread(() =>
            {
                FormSelection<ListBoxItemEntry> entrySelectionForm = new FormSelection<ListBoxItemEntry>(TracyFacade.Instance.LanguageManager.GetText("FormSelection_ImportEntries_Title"), TracyFacade.Instance.LanguageManager.GetText("FormSelection_ImportEntries_Message"), true);
                foreach (Entry entry in entries)
                {
                    entrySelectionForm.AddItem(new ListBoxItemEntry(entry));
                }
                if (entrySelectionForm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    List<ListBoxItemEntry> selectedItems = entrySelectionForm.GetSelectedItems();
                    if (selectedItems.Count > 0)
                    {
                        List<Entry> selectedEntries = new List<Entry>();
                        foreach (ListBoxItemEntry item in selectedItems)
                        {
                            selectedEntries.Add(item.Data);
                        }
                        callback(selectedEntries);
                    }
                    else
                    {
                        MessageBox.Show(TracyFacade.Instance.LanguageManager.GetText("MessageBox_NoEntrySelected_Message"));
                    }
                }
            });
        }

        public void SelectFolderForNewEntries(string defaultPath, Action<string> callback)
        {
            MessageBox.Show(TracyFacade.Instance.LanguageManager.GetText("MessageBox_SelectEntryParentFolder_Message"));
            //Select SavePath parent folder
            folderBrowserDialogMain.SelectedPath = defaultPath;
            if (folderBrowserDialogMain.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                callback(folderBrowserDialogMain.SelectedPath);
            }
        }
        #endregion

        #endregion

        #region NotifyIconView
        const int BALLOON_TIP_TIMEOUT = 10000; //10 seconds
        public event EventHandler BallonTipClicked;
        public event EventHandler TracyPreferencesClicked;
        public void DisplayMessage(string title, string text, ToolTipIcon icon = ToolTipIcon.Info)
        {
            notifyIconMain.ShowBalloonTip(BALLOON_TIP_TIMEOUT, title, text, icon);
        }
        private void notifyIconMain_BalloonTipClicked(object sender, EventArgs e)
        {
            ShowAndActivate();
            BallonTipClicked.InvokeEvent(this, e);
        }
        private void notifyIconMain_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                this.Visible = true;
                ShowAndActivate();
            }
        }
        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ShowAboutClicked.InvokeEvent(this, e);
        }
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }
        
        private void hideShowToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Visible = !this.Visible;
            if (this.Visible)
            {
                ShowAndActivate();
            }
        }

        private void consoleToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ShowAndActivate();
            if(!_formConsole.Visible) _formConsole.Show();
            _formConsole.BringToFront();
        }

        private void tracyPreferencesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            TracyPreferencesClicked.InvokeEvent(this, null);
        }

        FormConsole _formConsole = new FormConsole();
        public void DisplayException(string exceptionMessage, string detail)
        {
            InvokeOnUIThread(() =>
            {
                _formConsole.AppendMessage(detail);
                NotificationManager.Notify(this, TracyFacade.Instance.LanguageManager.GetText("Notification_ErrorOccurred_Title"), exceptionMessage, ToolTipIcon.Error, () =>
                {
                    if (!_formConsole.Visible) _formConsole.Show();
                    _formConsole.BringToFront();
                });
            });
        }
        #endregion

        

        //private void toolStripButton1_Click(object sender, EventArgs e)
        //{
        //    TracyFacade.Instance.ExceptionManager.Process(() =>
        //    {
        //        throw new Exception("test");
        //    },"UI Policy");
        //}


    }

}
